﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace Runtime.ADAggregator
{
    public class ADManager : MonoBehaviour
    {
        private static ADManager _instance;
        private static bool mIsCreate = false;
        private static bool mIsGMModel = false;

        public static ADManager Instance
        {
            get
            {
                if (_instance == null && !mIsCreate)
                {
                    var objs = FindObjectsOfType<ADManager>();
                    for (int i = 0; i < objs.Length; i++)
                    {
                        Destroy(objs[i]);
                    }

                    _instance = new GameObject().AddComponent<ADManager>();
                    _instance.name = "[GameUpdater] <color=yellow>NoInit<color>";
                    DontDestroyOnLoad(_instance);
                    _instance.InitTimeSystem();
                    mIsCreate = true;
                }

                return _instance;
            }
            private set => _instance = value;
        }

#if UNITY_ANDROID
        public AndroidJavaObject activityContext { get; private set; }
#endif

        /// <summary>
        /// 用于记录广告位状态 0 未加载 、 1 加载中、 2 加载成功
        /// </summary>
        private Dictionary<AD_Type, ADPlayer> AD_Dicts;

        private ADConfig _adConfig;

        private IAdController _adController;

        private AsyncAdPlayer _curAsyncPlayer;

        private string _userId;

        /// <summary>
        /// 全局任意视频广告播放结束后事件， bool 表示是否完成奖励
        /// </summary>
        public event Action<bool> GLOBAL_ShowAwardVideoComplete; 

        public string UserId => _userId;

#pragma warning disable CS0414
        private bool _isInit = false;
#pragma warning restore CS0414

        public void Init(Action onCallback, string userId, ADConfig adConfig, IAdController controller,
            params object[] args)
        {
            _isInit = true;
            _instance.name = "[GameUpdater] <color=green>Init<color>";
            AD_Dicts = new Dictionary<AD_Type, ADPlayer>();
            _userId = userId;
#if UNITY_EDITOR
            onCallback?.Invoke();
#else
            controller.Init(adConfig , args);
            _adController = controller;
            _adConfig = adConfig;
            onCallback?.Invoke();
#endif
        }

        /// <summary>
        /// 测试模式，此模式下，不会播放、加载任何广告，但是会模拟广告播放成功，正式版本不能调用此方法
        /// </summary>
        public void SetTestModel()
        {
            mIsGMModel = true;
        }

        public bool IsRealy(AD_Type adType)
        {
#if UNITY_EDITOR
            return true;
#endif
            if (!_isInit || mIsGMModel)
            {
                return true;
            }
#pragma warning disable CS0162
            if (AD_Dicts.ContainsKey(adType) == false)
            {
                AD_Dicts[adType] = PlayerCreate(adType);
            }

            return AD_Dicts[adType].IsReadly();
#pragma warning restore CS0162
        }

        public void LoadAD(AD_Type adType)
        {
#if UNITY_EDITOR
            return;
#endif
            if (!_isInit || mIsGMModel)
            {
                return;
            }
            // Debug.LogError("准备加载广告" + adType);
#pragma warning disable CS0162
            if (!IsRealy(adType))
            {
                AD_Dicts[adType].LoadAD();
            }
#pragma warning restore CS0162
        }

        /// <summary>
        /// 检查网络状态
        /// </summary>
        /// <returns></returns>
        public bool CheckNetwork()
        {
            return Application.internetReachability != NetworkReachability.NotReachable;
        }

        /// <summary>
        /// 直接加载并播放广告
        /// </summary>
        /// <param name="adType"></param>
        /// <param name="callback"></param>
        public void AsyncPlayAD(AD_Type adType, string adScene, Action<bool> callback)
        {
#if UNITY_EDITOR
            if (adType == AD_Type.AwardVideo)
            {
                this.OnVideoComplete(true);
            }
            callback?.Invoke(true);
            return;
#endif
            if (!_isInit || mIsGMModel)
            {
                callback?.Invoke(true);
                return;
            }
            _adController.EventLog("adScene", adScene);
            try
            {
                _curAsyncPlayer?.Kill();
                if (AD_Dicts.ContainsKey(adType) == false)
                {
                    AD_Dicts[adType] = PlayerCreate(adType);
                }

                var player = AD_Dicts[adType];
                _curAsyncPlayer = new AsyncAdPlayer(player, callback);
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                _adController.EventLog("error", "showAdError", e.Message);
                callback?.Invoke(false);
            }
        }

        public ADPlayer PlayerCreate(AD_Type type)
        {
#if UNITY_EDITOR
            return null;
#endif
            if (!_isInit || mIsGMModel)
            {
                return null;
            }
#pragma warning disable CS0162
            var adPlayer = _adController.CreateAdPlayer(type);
            adPlayer.ADType = type;
            return adPlayer;
#pragma warning restore CS0162
        }

        public void CloseAd(AD_Type adType)
        {
#if UNITY_EDITOR
            return;
#endif
            if (!_isInit || mIsGMModel)
            {
                return;
            }
#pragma warning disable CS0162
            if (adType != AD_Type.AwardVideo)
            {
                if (AD_Dicts.ContainsKey(adType))
                {
                    AD_Dicts[adType]?.CloseAD();
                }
            }
#pragma warning restore CS0162
        }


        #region TimeSystem

        private List<Action> _updateList;
        private const int DefaultLength = 1024;
        private List<AdTimeHandler> _timeHandlers;

        private void InitTimeSystem()
        {
            this._updateList = new List<Action>(DefaultLength);
            this._timeHandlers = new List<AdTimeHandler>();
        }

        private void _InvokeUpdate(List<Action> list)
        {
            for (int i = list.Count - 1; i >= 0; i--)
            {
                //在遍历时可能会出现外部操作list导致Count改变
                if (i >= list.Count)
                    continue;
                if (list[i] == null)
                {
                    list.RemoveAt(i);
                }
                else
                {
                    list[i].Invoke();
                }
            }

            for (int i = this._timeHandlers.Count - 1; i >= 0; i--)
            {
                var timeHandler = this._timeHandlers[i];
                if (timeHandler == null || timeHandler.IsDone || timeHandler._isKill)
                {
                    this._timeHandlers.RemoveAt(i);
                }
                else
                {
                    timeHandler.Update();
                }
            }
        }

        private void Update() => this._InvokeUpdate(this._updateList);

        public AdTimeHandler CreateTimer(float delay, Action callback, Action<float> update = null)
        {
            if (delay <= 0)
            {
                callback.Invoke();
                return null;
            }

            var timer = new AdTimeHandler(delay, callback, update);
            this._timeHandlers.Add(timer);
            return timer;
        }

        public AdTimeHandler CreateOneFrameTimer(Action callback, Action<float> update = null)
        {
            return this.CreateTimer(0.001f, callback, update);
        }

        public AdTimeHandler CreateTimer(GameObject gameObj, float delay, Action callback, Action<float> update = null)
        {
            if (delay <= 0)
            {
                callback.Invoke();
                return null;
            }

            var timer = new AdTimeHandler(gameObj, delay, callback, update);
            this._timeHandlers.Add(timer);
            return timer;
        }

        public void AddUpdater(Action updater)
        {
            this._updateList.Add(updater);
        }

        public void RemoveUpdater(Action updater)
        {
            this._updateList.Remove(updater);
        }

        #endregion

        public void CloseMask()
        {
            _adController.SetMask(false);
        }

        public void OpenMask()
        {
            _adController.SetMask(true);
        }

        internal void OnVideoComplete(bool isComplete)
        {
            GLOBAL_ShowAwardVideoComplete?.Invoke(isComplete);
        }
    }
}